#region Using Statements
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using DotNetEngine.Graphics;
using DotNetEngine.Screens;
using DotNetEngine.Utils;
using DotNetEngine.Input;

#endregion

namespace DotNetEngine.Core
{
    public class BaseGame : Game
    {
        //Static
        public static GraphicsDevice Device;
        public static ContentManager BaseContent;
        public static int Width;
        public static int Height;
        public static GameTime GameTime;
        public static SpriteBatch RenderTarget;
        public static List<DrawableElement> RenderElements;
        public static SpriteFont DefaultFont;
        public static Color BackgroungColor;
        public static bool GameExit;
        private static Stack<Screen> screens;

        //Public
        public GraphicsDeviceManager graphics;        

        #region Properties
        #endregion

        #region Inicialize Methods
        public BaseGame()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferWidth = 853;
            graphics.PreferredBackBufferHeight = 480;

            BaseContent = new ContentManager(Services);
            BackgroungColor = Color.White;
            RenderElements = new List<DrawableElement>();
            screens = new Stack<Screen>();

            GameExit = false;
        }

        protected sealed override void Initialize()
        {
            base.Initialize();

            Device = graphics.GraphicsDevice;
            Width = Device.Viewport.Width;
            Height = Device.Viewport.Height;
            RenderTarget = new SpriteBatch(GraphicsDevice);
            DefaultFont = BaseContent.Load<SpriteFont>(Directories.FontsDirectory + "Arial Black");

            InitializeGame();
        }

        protected virtual void InitializeGame() { }

        #endregion

        #region Public Methods
        public static void AddScreen(Screen sc)
        {
            sc.Initialize();
            sc.OnInitialize();
            screens.Push(sc);
        }
        public static void RemoveScreen()
        {
            screens.Peek().Dispose();
            screens.Pop();
            screens.Peek().OnInitialize();
        }

        protected sealed override void Update(GameTime gameTime)
        {
            if (GameExit)
            {
                BaseContent.Unload();
                Dispose();
                Exit();
            }

            BaseGame.GameTime = gameTime;

            //Update Game
            UpdateGame();

            //Update Input
            InputManager.Update();
            //Update Sound

            base.Update(gameTime);
        }

        public virtual void UpdateGame() 
        {
            //Update Currect Screen
            screens.Peek().Update();
        }

        protected sealed override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(BackgroungColor);

            //Draw Game
            DrawGame();

            //Sort Elements
            RenderElements.Sort(
                delegate(DrawableElement de1, DrawableElement de2) { return de1.Layer.CompareTo(de2.Layer); }
            );

            //Draw Scene
            RenderTarget.Begin();

            foreach (DrawableElement elem in RenderElements)
                elem.Draw();

            RenderTarget.End();

            //Clear Scene
            RenderElements.Clear();

            base.Draw(gameTime);
        }

        public virtual void DrawGame() 
        {
            //Draw Current Screen
            screens.Peek().Draw();
        }

        #endregion

        #region Private Methods
        #endregion
    }
}
